#pragma once

#include <cstdint>
#include <functional>
#include <memory>
#include "module_frame.hh"

using RPCTimeoutCB = std::function<void()>;

struct RPCCallBase {
    virtual ~RPCCallBase() {}
    uint64_t RPCID; // ID of RPC
    uint32_t timeout; // The timeout of RPC
    TimerID timerID; // The timer ID of RPC
    RPCTimeoutCB userTimeoutCB; // User timeout callback
    TimerCallback timerCB; // Engine timeout callback
};

// RPC class wrapper
template <typename ACKMETHOD>
struct RPCCall : public RPCCallBase {
    virtual ~RPCCall() {}
    ACKMETHOD ackMethod; // Use defined callback method for ACK
};

// RPC protocol header
struct ProtocolRPCHeader {
    std::uint32_t length; // packet length include header
    std::uint32_t msgID; // message ID
    std::uint32_t RPCHeaderLength; // locator message length
    // host endian to network endian
    void hton();
    // network endian to host endian
    void ntoh();
    // ctor
    ProtocolRPCHeader();
    // ctor
    // @param data stream
    ProtocolRPCHeader(const char* address);
    // Builds a header in data block
    void toBuffer(char* address);
};

// RPC Seleton base class
class RPCSkeletonBase {
public:
    // Dispose
    // @param RPCID ID of RPC
    // @param callBase The base class of RPC
    virtual void dispose(std::uint64_t RPCID, RPCCallBase* callBase) = 0;
    // To deal with the request message from path
    // @param pathID path ID
    // @param RPCID RPC ID
    // @param UUID The UUID of RPC call
    // @param data message
    // @param size message length
    virtual void onPathReq(PathID pathID, std::uint64_t RPCID, std::uint64_t UUID,
        const char* data, std::size_t size) = 0;
    // To deal with the acknowledge from path
    // @param RPCID RPC ID
    // @param callBase The class of RPC
    // @param data message
    // @param size message length
    virtual void onPathAck(std::uint64_t RPCID, RPCCallBase* callBase, const char* data, std::size_t size) = 0;
    // To deal with the request message from site
    // @param siteID site ID
    // @param RPCID RPC ID
    // @param UUID The UUID of RPC call
    // @param data message
    // @param size message length
    virtual void onSiteReq(const kratos::grid::SiteID & siteID, std::uint64_t RPCID, std::uint64_t UUID,
        const char * data, std::size_t size) = 0;
    // To deal with the acknowledge from site
    // @param RPCID RPC ID
    // @param callBase The class of RPC
    // @param data message
    // @param size message length
    virtual void onSiteAck(std::uint64_t RPCID, RPCCallBase* callBase, const char* data, std::size_t size) = 0;
    // To deal with the request message for entity 
    // @param pathID path ID
    // @param fromPathID the path ID the request originally sent out
    // @param entityID The entity ID
    // @param RPCID RPC ID
    // @param UUID The UUID of RPC call
    // @param data message
    // @param size message length
    virtual void onEntityReq(PathID pathID, PathID fromPathID, std::uint64_t entityID, std::uint64_t RPCID, std::uint64_t UUID,
        const char* data, std::size_t size) = 0;
    // To deal with the acknowledge from entity
    // @param RPCID RPC ID
    // @param callBase The class of RPC
    // @param data message
    // @param size message length
    virtual void onEntityAck(std::uint64_t RPCID, RPCCallBase* callBase, const char* data, std::size_t size) = 0;
};
